import json
import re
from ..users.models import User
from django.conf import settings
from django import http
from django.views import View
from django.contrib.auth import login
from meiduo_mall.settings.dev import logger
from QQLoginTool.QQtool import OAuthQQ
from django_redis import get_redis_connection
from meiduo_mall.utils.secret import SecretOauth
from .models import OAuthQQUser

"""提供QQ登录页面网址"""
class QQURLView(View):

    def get(self, request):
        # next 表示从哪个页面进入到的登录页面
        # 将来登录成功后，就自动回到那个页面
        next = request.GET.get('next')

        # 获取 QQ 登录页面网址
        # 创建 OAuthQQ 类的对象
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI,
                        state=next)

        # 调用对象的获取 qq 地址方法
        login_url = oauth.get_qq_url()

        # 返回登录地址
        return http.JsonResponse({'code': 0,  'errmsg': 'OK', 'login_url':login_url})

"""用户扫码登录的回调处理"""
class QQUserView(View):

    def get(self, request):
        # 获取前端发送过来的 code 参数:
        code = request.GET.get('code')
        #校验
        if not code:
            # 判断 code 参数是否存在
            return http.JsonResponse({'code': 400,
                                      'errmsg': '缺少code参数'})

        # 调用我们安装的 QQLoginTool 工具类，进行美多后台认证
        # 1.创建工具对象
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI)

        try:
            # 2.携带 code 向 QQ服务器 请求 access_token
            #code --------> token
            access_token = oauth.get_access_token(code)

            # 3.携带 access_token 向 QQ服务器 请求 openid
            # token ----------> openid
            openid = oauth.get_open_id(access_token)
            # 判断是否绑定 openid
            response = is_bind_openid(request, openid)
            return response
        except Exception as e:
            # 如果上面获取 openid 出错, 则验证失败
            logger.error(e)
            # 返回结果
            return http.JsonResponse({'code': 400, 'errmsg': 'oauth2.0认证失败, 即获取qq信息失败'})

    def post(self, request):
        # 1.解析参数 json
        data_dict = json.loads(request.body.decode())
        mobile = data_dict.get('mobile')
        password = data_dict.get('password')
        sms_code_client = data_dict.get('sms_code')
        access_token = data_dict.get('access_token')  # openid

        # 2.校验参数 判空 判正则 短信验证码
        # 判断参数是否齐全
        if not all([mobile, password, sms_code_client]):
            return http.JsonResponse({'code': 400,
                                      'errmsg': '缺少必传参数'})

        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.JsonResponse({'code': 400,
                                      'errmsg': '请输入正确的手机号码'})

        # 判断密码是否合格
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.JsonResponse({'code': 400,
                                      'errmsg': '请输入8-20位的密码'})

        # 3.判断短信验证码是否一致
        # 创建 redis 链接对象:
        redis_conn = get_redis_connection('verify_code')

        # 从 redis 中获取 sms_code 值:
        sms_code_server = redis_conn.get('sms_%s' % mobile)

        # 判断获取出来的有没有:
        if sms_code_server is None:
            # 如果没有, 直接返回:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '验证码失效'})
        # 如果有, 则进行判断:
        if sms_code_client != sms_code_server.decode():
            # 如果不匹配, 则直接返回:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '输入的验证码有误'})

            # 3.判断openid 是否有值 -- 解密 前端给后台 的加密 openid
        openid = SecretOauth().loads(access_token).get('openid')

        if not openid:
            return http.JsonResponse({'code': 400, 'errmsg': 'openid为空!'})

        # 4.判断mobile 的用户是否存在
        try:
            user = User.objects.get(mobile=mobile)
        except Exception as e:
            # 新用户
            print(e)
            user = User.objects.create_user(username=mobile, mobile=mobile, password=password)
        else:
            # 判断密码是否正确
            if not user.check_password(password):
                return http.JsonResponse({'code': 400, 'errmsg': '密码错误!'})

        # 5.绑定openid 入库
        try:
            OAuthQQUser.objects.create(user=user, openid=openid)
        except Exception as e:
            print('绑定错误原因',e)

        # 6.保持登录状态 设置cookie
        # 1. 保持登录状态 login()
        login(request, user)
        # 2.设置cookie username
        response = http.JsonResponse({'code': 0, 'errmsg': '绑定成功!'})
        response.set_cookie('username', user.username, max_age=3600 * 24 * 14)
        # 3.返回响应 JSON code:0
        return response

# 判断是否绑定 openid
def is_bind_openid(request, openid):
    try:
        oauth_qq = OAuthQQUser.objects.get(openid=openid)
    except OAuthQQUser.DoesNotExist as e:

        logger.error(e)
        # 没有 绑定 openid
        # 后端 需要 把 加密过的 openid 传递给 绑定页面  的前端
        secret_openid = SecretOauth().dumps({'openid': openid})
        return http.JsonResponse({'code': 300, 'errmsg': '未绑定', 'access_token': secret_openid})

    else:
        # 绑定 openid
        user = oauth_qq.user
        # 1. 保持登录状态 login()
        login(request, user)
        # 2.设置cookie username
        response = http.JsonResponse({'code': 0, 'errmsg': '成功!'})
        response.set_cookie('username', user.username, max_age=3600 * 24 * 14)
        # 3.返回响应 JSON code:0
        return response
